#pragma once

#include<iostream>
#include<sys/epoll.h>
#include"Socket.hpp"
#include"Epoller.hpp"
#include<memory>

using namespace std;

uint32_t EVENT_IN = (EPOLLIN);
uint32_t EVENT_OUT = (EPOLLOUT);

class EpollServer:public Nocopy
{
    static const int num = 64;
public:
    EpollServer(uint16_t port)
    :_port(port)
    ,_listensock_ptr(new Sock())
    ,_epoller_ptr(new Epoller())
    {}

    void Init()
    {
        _listensock_ptr->Socket();
        _listensock_ptr->Bind(_port);
        _listensock_ptr->Listen();
        lg(Info, "create listen socket success: %d", _listensock_ptr->GetFd());
    }

    void Accepter()
    {
        //获取了一个新连接
        string clientip;
        uint16_t clientport;
        int sock = _listensock_ptr->Accept(&clientip, &clientport);
        if(sock > 0){
            //我们能直接读取吗？不能！
            _epoller_ptr->EpllerUpdate(EPOLL_CTL_ADD, sock, EVENT_IN);
        }
        else{
            return;
        }
    }

    void Recver(int fd, int i)
    {
        char buffer[1024];
        ssize_t n = read(fd, buffer, sizeof(buffer)-1);
        if(n > 0)
        {
            buffer[n] = 0;
            cout<<"get a message: "<<buffer<<endl;
        }
        else if(n == 0)
        {
            lg(Info, "client quit, close fd is : %d", fd);
            //先移除后关闭
            _epoller_ptr->EpllerUpdate(EPOLL_CTL_DEL, fd, 0);
            close(fd);
        }
        else
        {
            lg(Warning, "read error, close fd is : %d", fd);
            _epoller_ptr->EpllerUpdate(EPOLL_CTL_DEL, fd, 0);
            close(fd);
        }
    } 

    void Dispatcher(struct epoll_event revs[], int num)
    {
        for(int i = 0; i<num; i++)
        {
            uint32_t event = revs[i].events;
            int fd = revs[i].data.fd;
            if(event & EVENT_IN){
                if(fd == _listensock_ptr->GetFd()){
                    Accepter();
                }
                else{
                    //其它fd上的事件就绪
                    Recver(fd, i);
                }
            }
            else
            {

            }
        }
    }
    void Start()
    {
        //将listensock添加到epoll中
        _epoller_ptr->EpllerUpdate(EPOLL_CTL_ADD, _listensock_ptr->GetFd(), EVENT_IN);
        struct epoll_event revs[num];
        while(true)
        {
            int n = _epoller_ptr->EpollWait(revs, num);
            if(n > 0)
            {
                //有事件就绪
                lg(Debug, "event happened , fd is: %d", revs[0].data.fd);
                Dispatcher(revs, n);
            }
            else if(n == 0)
            {
                lg(Info, "time out...");
            }
            else
            {
                lg(Error, "epoll wait...");
            }
        }
    }
    

    ~EpollServer()
    {
        _listensock_ptr->Close();
    }
private:
    uint16_t _port;
    std::shared_ptr<Sock> _listensock_ptr;
    std::shared_ptr<Epoller> _epoller_ptr;
};